//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/** @author  John A. Miller
 *  @author  Michael E. Cotterell
 *  @see     LICENSE (MIT style license file).
 */

package simopt

import scalation.process._

import scalation.linalgebra.{ MatrixD, VectorD }
import scalation.linalgebra_gen.Vectors.VectorI
import scalation.queueingnet.JacksonNet 
import scalation.optima.IntegerTabuSearch

// Queueing Model for Healthcare Application
class ERQueueingModel (x: VectorI) extends ERParams
{
    //                       DESTINATIONS                        S
    //                       TN    RN    MD    NP    AC          O  
    val p = MatrixD ((5, 5), 0.00, 1.00, 0.00, 0.00, 0.00, // TN U
                             0.00, 0.00, 0.25, 0.75, 0.00, // RN R
                             0.00, 0.00, 0.00, 0.00, 1.00, // MD C 
                             0.00, 0.00, 0.00, 0.00, 1.00, // NP E
                             0.00, 0.00, 0.00, 0.00, 0.00) // AC S

    val jqn = new JacksonNet (p, lambda, mu(0), x) // create model
    
    // calculate expected number and waiting time in the system
    val n   = (0 until jqn.m).map(i => jqn.nQueue(i) + jqn.rho(i) * x(i)).sum
    val w   = (0 until jqn.m).map(i => jqn.nQueue(i) / jqn.lambda(i)).sum

} // ERQueueingModel

object ERQueueingModelTest extends App  
{
    val x0 = new VectorI (1, 1, 1, 1, 1)
    val qm = new EmergencyJacksonModel (x0)
    qm.jqn.check
    qm.jqn.report
} // ERQueueingModelTest

trait ERQueueingOpt extends ERParams
{
    // Utility Function for Healthcare Application 
    // Uses the Queueing Model
    def u_q (x: VectorI): Double = {
        for (i <- 0 until x.dim if x(i) < 1)  return Double.NegativeInfinity
        for (i <- 0 until x.dim if x(i) > 10) return Double.NegativeInfinity
        _u_q (x)
    } // u_q

    // Utility Function for Healthcare Application 
    // Uses the Queueing Model
    // Note: This version is used with Multiple Linear Regression
    def _u_q (x: VectorI): Double = {
        val m = new ERQueueingModel (x) // create queueing model
        val c = x dot s                 // operating payroll cost
        val r = f(0) * m.n              // revenue for patient service
        val p = r - c                   // net profit
        p - d * m.w * m.n               // return overall utility
    } // u_q

} // ERQueueingOpt

object ERQueueingOptTest extends App with ERQueueingOpt 
{
    val x0          = VectorI (1, 1, 1, 1, 1)             // starting point
    val its         = new IntegerTabuSearch (u_q)         // setup optimizer
    val (x, result) = its.maximize (x0)                   // get results
    println ("x = %s; u_q value = %f".format(x, result))  // print results
} // ERQueueingOptTest
